Provisioning with Terraform
Terraform (terraform/hetzner-main/ in the automation repo) provisions the raw VM hardware, networking, and Cloud-Init settings on the Proxmox cluster. It does not install any software inside the VMs — that's Ansible's job, see Configuring with Ansible.
Provisioning is decoupled from configuration
make provision (terraform apply) creates or resizes VMs and is a rare, deliberate action. The per-VM setup-* / update-* Make targets only run Ansible against an already-existing VM and never trigger a Terraform apply. Run make provision first if a VM doesn't exist yet; otherwise you almost never need it.
VM specs
Every VM is a full clone of the shared debian-13-template (see below), on bridge vmbr1, with the QEMU guest agent enabled so Terraform can detect boot completion and IP assignment.
| VM | Terraform file | VMID | Cores | Memory | Disk |
|---|---|---|---|---|---|
| docker-build | docker-build.tf | 112 | 2 | 8 GB | 50 GB |
| synthesis-test | synthesis-test.tf | 113 | 4 | 4 GB | 32 GB |
| webserver | webserver.tf | 114 | 4 | 4 GB | 16 GB |
| observability | observability.tf | 115 | 2 | 4 GB | 64 GB |
| api-gateway | api-gateway.tf | 117 | 2 | 2 GB | 16 GB |
| services-user | services-user.tf | 118 | 4 | 4 GB | 32 GB |
| services-staff | services-staff.tf | 119 | 4 | 4 GB | 64 GB |
Amergin is a dedicated GPU server outside this Terraform configuration entirely — it's provisioned manually and configured by Ansible only.
Resizing an existing VM
There's no CPU/memory hotplug, so a resize always needs a cold boot — terraform apply alone won't do it live. For webserver and services-staff specifically, resize directly on the Proxmox host instead of through Terraform, then update the .tf file's values to match so Terraform shows no drift on the next plan:
qm shutdown <vmid>
qm set <vmid> --cores <N> --memory <M>
qm start <vmid>
See the Webserver page for why resizing that particular VM through Terraform can break Terraform's own access to the Proxmox API, and for the SSH host-key fixup a resize also requires.
Creating the base template
New VMs are cloned from a shared debian-13-template (VMID 9000). This isn't automated yet — build it by hand on the Proxmox host as root:
apt update && apt install libguestfs-tools -y
# Download the current Debian 13 (Trixie) generic cloud image
wget https://cloud.debian.org/images/cloud/trixie/latest/debian-13-generic-amd64.qcow2
# Inject qemu-guest-agent into the image offline — needed for clean
# shutdowns, reliable snapshots, and for Terraform to detect boot/IP assignment
virt-customize -a debian-13-generic-amd64.qcow2 --install qemu-guest-agent
# Create the VM shell and import the modified disk
qm create 9000 --name "debian-13-template" --memory 2048 --cores 2 --net0 virtio,bridge=vmbr0
qm importdisk 9000 debian-13-generic-amd64.qcow2 local
qm set 9000 --scsihw virtio-scsi-pci --scsi0 local:9000/vm-9000-disk-0.raw
qm set 9000 --ide2 local:cloudinit
qm set 9000 --boot c --bootdisk scsi0
qm set 9000 --serial0 socket --vga serial0
# Convert to a reusable template, then clean up the downloaded image
qm template 9000
rm debian-13-generic-amd64.qcow2